namespace RBAC.Write.Api.Application.Handler.ERP.InboundManagement
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using MediatR;
    using Microsoft.Extensions.Logging;
    using RBAC.Domain.Dto.Output;
    using RBAC.Domain.MaterialManage;
    using RBAC.Domain.StorageManage;
    using RBAC.ErrorCode;
    using RBAC.Interstructrue.Base;
    using RBAC.Write.Api.Application.Command.ERP.InboundManagement;

    public class UpdatePurchaseStorageHandler
        : IRequestHandler<UpdatePurchaseStorageCommand, APIResult<bool>>
    {
        private readonly IBaseRepository<PurchaseStorage> headerRepo;
        private readonly IBaseRepository<PurchaseStorageDetail> detailRepo;
        private readonly IBaseRepository<Mater> materRepo;
        private readonly ILogger<UpdatePurchaseStorageHandler> logger;

        public UpdatePurchaseStorageHandler(
            IBaseRepository<PurchaseStorage> headerRepo,
            IBaseRepository<PurchaseStorageDetail> detailRepo,
            IBaseRepository<Mater> materRepo,
            ILogger<UpdatePurchaseStorageHandler> logger)
        {
            this.headerRepo = headerRepo;
            this.detailRepo = detailRepo;
            this.materRepo = materRepo;
            this.logger = logger;
        }

        public Task<APIResult<bool>> Handle(UpdatePurchaseStorageCommand request, CancellationToken cancellationToken)
        {
            var result = new APIResult<bool>();
            try
            {
                if (request.Id <= 0)
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = "无效的主表ID";
                    result.Data = false;
                    return Task.FromResult(result);
                }
                if (request.Data == null || request.Data.Details == null || request.Data.Details.Count == 0)
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = "明细不能为空";
                    result.Data = false;
                    return Task.FromResult(result);
                }

                // 校验单据是否存在
                var header = headerRepo.GetFirstOrDefault("Id = @Id AND IsDeleted = 0", new { Id = request.Id });
                if (header == null)
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = "单据不存在或已删除";
                    result.Data = false;
                    return Task.FromResult(result);
                }

                // 仅审批状态允许编辑
                if (string.IsNullOrWhiteSpace(header.OrderStatus) || header.OrderStatus != "审批")
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = "仅审批状态的单据允许编辑";
                    result.Data = false;
                    return Task.FromResult(result);
                }

                var dto = request.Data;

                // 校验：明细中存在非空跟单编号(SalesOrderCode)时，是否被其他入库单明细占用（排除当前单据）
                var followCodes = dto.Details
                    .Where(d => !string.IsNullOrWhiteSpace(d.SalesOrderCode))
                    .Select(d => d.SalesOrderCode!.Trim())
                    .Distinct()
                    .ToList();
                if (followCodes.Count > 0)
                {
                    var placeholders = string.Join(",", followCodes.Select((_, i) => $"@C{i}"));
                    var paramCodes = followCodes
                        .Select((c, i) => new { Key = $"@C{i}", Value = (object)c })
                        .ToDictionary(x => x.Key, x => x.Value);
                    paramCodes["@CurId"] = request.Id;
                    var existCode = headerRepo.QueryFirstOrDefault<string>(
                        $"SELECT d.SalesOrderCode FROM PurchaseStorageDetail d WHERE d.IsDeleted = 0 AND d.SalesOrderCode IN ({placeholders}) AND d.PurchaseStorageId <> @CurId LIMIT 1",
                        paramCodes);
                    if (!string.IsNullOrWhiteSpace(existCode))
                    {
                        result.Code = APIEnums.Fail;
                        result.Msg = $"{existCode}单据已生成入库单";
                        result.Data = false;
                        return Task.FromResult(result);
                    }
                }

                // 校验物料是否存在
                var materIds = dto.Details.Select(d => d.MaterId).Distinct().ToList();
                if (materIds.Count > 0)
                {
                    var inClause = string.Join(",", materIds.Select((_, index) => $"@Id{index}"));
                    var parameters = materIds.Select((id, index) => new { Key = $"@Id{index}", Value = id })
                        .ToDictionary(x => x.Key, x => (object)x.Value);
                    var maters = materRepo.GetAll($"Id IN ({inClause})", parameters);
                    var validMaterIds = new HashSet<long>(maters.Select(m => m.Id));
                    var missing = materIds.Where(id => !validMaterIds.Contains(id)).ToList();
                    if (missing.Any())
                    {
                        result.Code = APIEnums.Fail;
                        result.Msg = $"存在无效物料ID: {string.Join(",", missing)}";
                        result.Data = false;
                        return Task.FromResult(result);
                    }
                }

                var now = DateTime.Now;

                // 构建事务SQL：更新主表(不更新OrderCode)、删除旧明细、插入新明细
                var sqlHead = @"START TRANSACTION;
UPDATE PurchaseStorage SET 
    OrderType = @OrderType,
    BusinessType = @BusinessType,
    Operator = @Operator,
    Warehouse = @Warehouse,
    OrderDate = @OrderDate,
    BusinessStatus = @BusinessStatus,
    ArrivalNo = @ArrivalNo,
    OrderStatus = @OrderStatus,
    BusinessDept = @BusinessDept,
    Supplier = @Supplier,
    BusinessPerson = @BusinessPerson,
    Period = @Period,
    Remark = @Remark,
    CreateUser = @CreateUser,
    CreateTime = @CreateTime
WHERE Id = @Id AND IsDeleted = 0;
DELETE FROM PurchaseStorageDetail WHERE PurchaseStorageId = @Id;";

                var detailSqlParts = new List<string>();
                for (int i = 0; i < dto.Details.Count; i++)
                {
                    detailSqlParts.Add($"INSERT INTO PurchaseStorageDetail (PurchaseStorageId, MaterId, SalesOrderCode, Num, Remark, CreateUser, CreateTime, IsDeleted) VALUES (@Id, @D{i}_MaterId, @D{i}_SalesOrderCode, @D{i}_Num, @D{i}_Remark, @CreateUser, @CreateTime, false);");
                }
                var sqlTail = "COMMIT;";
                var fullSql = sqlHead + "\n" + string.Join("\n", detailSqlParts) + "\n" + sqlTail;

                var param = new Dictionary<string, object?>
                {
                    ["Id"] = request.Id,
                    ["OrderType"] = dto.OrderType ?? header.OrderType,
                    ["BusinessType"] = dto.BusinessType ?? header.BusinessType,
                    ["Operator"] = dto.Operator ?? header.Operator,
                    ["Warehouse"] = dto.Warehouse ?? header.Warehouse,
                    ["OrderDate"] = dto.OrderDate ?? header.OrderDate ?? now,
                    ["BusinessStatus"] = dto.BusinessStatus ?? header.BusinessStatus,
                    ["ArrivalNo"] = dto.ArrivalNo ?? header.ArrivalNo,
                    ["OrderStatus"] = dto.OrderStatus ?? header.OrderStatus,
                    ["BusinessDept"] = dto.BusinessDept ?? header.BusinessDept,
                    ["Supplier"] = dto.Supplier ?? header.Supplier,
                    ["BusinessPerson"] = dto.BusinessPerson ?? header.BusinessPerson,
                    ["Period"] = dto.Period ?? header.Period,
                    ["Remark"] = dto.Remark ?? header.Remark,
                    ["CreateUser"] = dto.CreateUser ?? header.CreateUser,
                    ["CreateTime"] = now
                };

                for (int i = 0; i < dto.Details.Count; i++)
                {
                    var d = dto.Details[i];
                    param[$"D{i}_MaterId"] = d.MaterId;
                    param[$"D{i}_SalesOrderCode"] = d.SalesOrderCode;
                    param[$"D{i}_Num"] = d.Num;
                    param[$"D{i}_Remark"] = d.Remark;
                }

                try
                {
                    headerRepo.Execute(fullSql, param);
                }
                catch (Exception)
                {
                    headerRepo.Execute("ROLLBACK;");
                    throw;
                }

                result.Code = APIEnums.Success;
                result.Msg = "编辑采购入库成功";
                result.Data = true;
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "编辑采购入库失败: {Message}", ex.Message);
                result.Code = APIEnums.Error;
                result.Msg = "编辑采购入库失败";
                result.Data = false;
            }

            return Task.FromResult(result);
        }
    }
}
